//
//  HistoryVariable.m
//  histoval
//
//  Created by Daniel Braun on 14/06/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "HistoryVariable.h"
#import "EDSortedArray.h"
#import "EDSortedArrayExtension.h"


@implementation HistoEntry
- (void) dealloc {
	[super dealloc];
}

- (id) init {
	self = [super init];
	if (self != nil) {
		//<#initializations#>
	}
	return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{
	[super encodeWithCoder:coder];
	if ( [coder allowsKeyedCoding] ) {
		[coder encodeDouble:_value forKey:@"value"];
	}
}

- (id) initWithCoder:(NSCoder *) coder
{
	self=[super initWithCoder:coder];
	if ([coder allowsKeyedCoding]) {
		_value=[coder decodeDoubleForKey:@"value"];
		return self;
	}
failed:
	[self release];
	return nil;
}

- initWithValue:(double)v date:(NSDate *)d
{
	self = [super initWithDate:d];
	if (self != nil) {
		_value=v;
	}
	return self;
}

@end

@implementation HistoryVariable

- (void) dealloc {
	[super dealloc];
}

- (id) init {
	self = [super init];
	if (self != nil) {
		//comparator = @selector(dateCompare:);
	}
	return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{
	[super encodeWithCoder:coder];
	if ( [coder allowsKeyedCoding] ) {
		//[coder encodeObject:historic forKey:@"historic"];
	}
}

- (id) initWithCoder:(NSCoder *) coder
{
	self=[super initWithCoder:coder];
	if (self && [coder allowsKeyedCoding]) {
		//
		return self;
	}
failed:
	[self release];
	return nil;
}

- (void) setValue:(NSNumber *)v atDate:(NSDate *)date
{
	[self setDValue:[v doubleValue]  atDate:date];
}

- (void) setDValue:(double)val atDate:(NSDate *)d
{
	HistoEntry *v=[[HistoEntry alloc]initWithValue:val date:d];
	[self addObject:v];
	[v release];
}
- (void) setValue:(NSNumber *)v
{
	[self setDValue:[v doubleValue] atDate:[NSDate date]];
}

- (void) setDValue:(double )v
{
	[self setDValue:v atDate:[NSDate date]];
}
- (NSNumber *) value
{
	HistoEntry *h=[self maximumObject];
	return [NSNumber numberWithDouble:h->_value];
}
- (double) dvalue
{
	HistoEntry *h=[self maximumObject];
	return h->_value;
}

- (double) dvalueAtDate:(NSDate *)d
{
	HistoEntry *vref=[[HistoEntry alloc]initWithValue:0.0 date:d];
	HistoEntry *v=[self smallerOrEqualMember:vref];
	[vref release];
	if (!v) {
		NSLog(@"dvalueAtDate, no object for date %@\n", d);
		return 0.0;
	}
	return v->_value;
}

- (NSNumber *) valueAtDate:(NSDate *)date
{
	return [NSNumber numberWithDouble:[self dvalueAtDate:date]];
}

- (NSNumber *) averageValueBetween:(NSDate *)d1 and:(NSDate *)d2
{
	return [NSNumber numberWithDouble:[self daverageValueBetween:d1 and:d2]];
}

- (double) daverageValueBetween:(NSDate *)d1 and:(NSDate *)d2
{
	double total=0.0;
	int count=0;
	HistoEntry *vref=[[HistoEntry alloc]initWithValue:0.0 date:d1];
	HistoEntry *v1=[self smallerOrEqualMember:vref];
	if (!v1) {
		v1=[self successorForObject:vref];
	} else {
		if ([v1 dateCompare:vref]!=NSOrderedSame) {
			v1=[self successorForObject:v1];
		}
	}
	while (v1) {
		if ([v1->date compare:d2]==NSOrderedDescending) break;
		if (0) NSLog(@"   avg using value %g at date %@ (%g)\n",
		      v1->_value, v1->date, [v1->date timeIntervalSinceNow]);
		total += v1->_value;
		count ++;
		v1=[self successorForObject:v1];
	}
	if (count<=0) {
		NSLog(@"averageValueBetween, not enough samples\n");
		return 0.0;
	}
	return total/count;
}

- (double) evolutionBetween:(NSDate *)d1 and:(NSDate *)d2
{
	double total=0.0;
	double dv;
	NSTimeInterval dt;
	NSTimeInterval tt;
	tt=[d2 timeIntervalSinceDate:d1];
	int count=0;
	HistoEntry *vref=[[HistoEntry alloc]initWithValue:0.0 date:d1];
	HistoEntry *v1=[self smallerOrEqualMember:vref];
	if (!v1) {
		v1=[self successorForObject:vref];
	} else {
		if ([v1 dateCompare:vref]!=NSOrderedSame) {
			v1=[self successorForObject:v1];
		}
	}
	BOOL first=YES;
	double val, pval;
	double var;
	NSDate *date=nil;
	NSDate *pdate=nil;
	while (v1) {
		if ([v1->date compare:d2]==NSOrderedDescending) break;
		pdate=date;
		pval=val;
		date=v1->date;
		val=v1->_value;
		if (first) {
			first=NO;
			v1=[self successorForObject:v1];
			continue;
		}
		dv=val-pval;
		dt=[date timeIntervalSinceDate:pdate];
		NSAssert(dt>0, @"bouh");
		if (!dt) continue;
		var=(dv/dt)*(dt/tt);
		total+=var;
		count ++;
		v1=[self successorForObject:v1];
	}
	if (count<=0) {
		NSLog(@"averageValueBetween, not enough samples\n");
		return 0.0;
	}
	return total;
}

- (NSNumber *) interpolatedValueAtDate:(NSDate *)date
{
	return [NSNumber numberWithDouble:[self interpolatedDValueAtDate:date]];
}

- (double) interpolatedDValueAtDate:(NSDate *)date
{
	HistoEntry *e1;
	HistoEntry *e2;
	HistoEntry *vref1=[[[HistoEntry alloc]initWithValue:0.0 date:date]autorelease];
	e1=[self smallerOrEqualMember:vref1];
	if (!e1) { 
		return 0.0;
	}
	e2=[self successorForObject:e1];
	if (!e2) {
		if ([e1->date compare:date]==NSOrderedSame) return e1->_value;
		return 0.0;
	}
	double d1=[date timeIntervalSinceDate:e1->date];
	double d2=[e2->date timeIntervalSinceDate:date];
	NSAssert(d1>=0, @"pb here");
	NSAssert(d2>=0, @"pb here");
	double r=(e1->_value * d2 / (d1+d2)) + (e2->_value * d1 / (d1+d2));
	return r;
}


@end
